package pers.yefeng.config;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.scheduling.annotation.EnableAsync;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;

import java.util.concurrent.ThreadPoolExecutor;

/**
 * 线程池配置
 */
@Configuration
@EnableAsync
public class ThreadPoolTaskConfig {


    /**
     * 核心线程数：线程池创建时候初始化的线程数。当线程数超过核心线程数，则超过的线程则进入任务队列。
     * 最大线程数：只有在任务队列满了之后才会申请超过核心线程数的线程。不能小于核心线程数。
     * 任务队列：线程数大于核心线程数的部分进入任务队列。如果任务队列足够大，超出核心线程数的线程不会被创建，它会等待核心线程执行完它们自己的任务后再执行任务队列的任务，而不会再额外地创建线程。
     * 举例：如果有20个任务要执行，核心线程数：10，最大线程数：20，任务队列大小：2。则系统会创建18个线程。这18个线程有执行完任务的，再执行任务队列中的任务。
     * <p>
     * 线程的空闲时间：当 线程池中的线程数量 大于 核心线程数 时，如果某线程空闲时间超过 keepAliveTime ，线程将被终止。这样，线程池可以动态的调整池中的线程数。
     * 拒绝策略：如果（总任务数 - 核心线程数 - 任务队列数）-（最大线程数 - 核心线程数）> 0 的话，则会出现线程拒绝。举例：( 12 - 5 - 2 ) - ( 8 - 5 ) > 0，会出现线程拒绝。线程拒绝又分为 4 种策略，分别为：
     * CallerRunsPolicy()：交由调用方线程运行，比如 main 线程。
     * AbortPolicy()：直接抛出异常。
     * DiscardPolicy()：直接丢弃。
     * DiscardOldestPolicy()：丢弃队列中最老的任务。
     */

    @Bean
    public ThreadPoolTaskExecutor executor() {
        ThreadPoolTaskExecutor executor = new ThreadPoolTaskExecutor();
        //设置核心线程数
        executor.setCorePoolSize(20);
        //设置最大线程数
        executor.setMaxPoolSize(500);
        //除核心线程外的线程存活时间(秒)
        executor.setKeepAliveSeconds(60);
        //如果传入值大于0，底层队列使用的是LinkedBlockingQueue,否则默认使用SynchronousQueue
        executor.setQueueCapacity(20);
        //线程名称前缀
        executor.setThreadNamePrefix("AStream");
        //设置拒绝策略
        executor.setRejectedExecutionHandler(new ThreadPoolExecutor.CallerRunsPolicy());
        return executor;
    }

}
